<?php
/**
 * Created by PhpStorm.
 * User: 73640
 * Date: 2018/11/8
 * Time: 11:38
 */

namespace App\Service;


use App\BrokerCall;
use App\BrokerMedia;
use App\Exceptions\ApiException;
use App\Exceptions\TeleException;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Stream;
use Illuminate\Support\Facades\Log;
use App\model\BrokerMobile;

class TeleService
{
    protected $key;
    protected $id;
    protected $url;
    private  $client;
    private  $notifyCallUrl='http://requestbin.leo108.com/1j1iv8d1';//话单通知地址
    private  $notifyMtReceUrl='http://requestbin.leo108.com/1j1iv8d1';//商务号发送短信后收到的状态报告
    private  $notifyMoUrl='http://requestbin.leo108.com/1j1iv8d1'; //商务号收到短信后，调用该通知地址
    private  $notifyAudioStatusUrl;//媒体音状态变更回送通知地址
    private  $notifyMediaStreamUrl;//媒体音通知地址
    private  $notifyAuthStatusUrl;//用户认证状态变更通知地址
    private  $notifySecretRelationshipUrl;//保密号生成和解绑通知地址
    private  $syncRelationshipUrl;//保密号关系每日同步通知地址
    public function __construct()
    {
        $this->client=new Client();
        $this->key=config('tele.key');
        $this->id=config('tele.id');
        $this->url=config('tele.url');
        $this->notifyCallUrl=config('app.url').'/api/notifyCallUrl';
        $this->notifyMediaStreamUrl=config('app.url').'/api/notifyMediaStreamUrl';
    }
    public function setSpInfo(){//1. 商户参数设置接口
        $uri='setSpInfo.do';
        $params=[
            'id'=>$this->id,
            'timestamp'=>$this->createTimeStamp(),
            'notifyCallUrl'=>$this->notifyCallUrl,//话单通知地址
            'notifyMtReceUrl'=>$this->notifyMtReceUrl,
            'notifyMoUrl'=>$this->notifyMoUrl,
        ];
        $sign=$this->sign($params);
        $params['notifyAudioStatusUrl']=$this->notifyAudioStatusUrl;
        $params['notifyMediaStreamUrl']=$this->notifyMediaStreamUrl;
        $params['notifyAuthStatusUrl']=$this->notifyAuthStatusUrl;
        $params['notifySecretRelationshipUrl']=$this->notifySecretRelationshipUrl;
        $params['syncRelationshipUrl']=$this->syncRelationshipUrl;
        $params['sign']=$sign;
        return   $this->postdata($uri,$params);
    }

    /**
     * @param string $blockMobile
     * @param int $type
     * @param int $isDelete
     * @return mixed|\Psr\Http\Message\StreamInterface|string
     * @throws ApiException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function setSpBlockMobile(string  $blockMobile,int $type=0,int $isDelete=0){// 商户全局黑名单设置接口
        $uri='setSpBlockMobile.do';
        $params=[
            'id'=>$this->id,
            'timestamp'=>$this->createTimeStamp(),
            'blockMobile'=>$blockMobile,//话单通知地址
            'type'=>$type,//0关机 2默认
            'isDelete'=>$isDelete,//0增加 1 取消
        ];
        $sign=$this->sign($params);
        $params['sign']=$sign;
        return   $this->postdata($uri,$params);
    }

    /**
     * @param string $mobile
     * @param int $isDelete
     * @return mixed|\Psr\Http\Message\StreamInterface|string
     * @throws ApiException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function setWhiteMobile(string  $mobile,int $isDelete){//3. 商户全局白名单设置接口
        $uri='setSpBlockMobile.do';
        $params=[
            'id'=>$this->id,
            'timestamp'=>$this->createTimeStamp(),
            'mobiles'=>$mobile,//话单通知地址
            'isDelete'=>$isDelete,//0增加 1 取消
        ];
        $sign=$this->sign($params);
        $params['sign']=$sign;
        return   $this->postdata($uri,$params);
    }
    /**
     * @param $boker_id
     * @param string $mobile
     * @param string $virtualMobile
     * @return mixed|\Psr\Http\Message\StreamInterface|string
     * @throws ApiException
     */
    public function bindMobile($seqId,string $mobile,string $virtualMobile){//绑定手机
        $uri='bindMobile.do';
        $params=[
            'id'=>$this->id,
            'seqId'=>(string)$seqId,
            'timestamp'=>$this->createTimeStamp(),
            'bindMobile'=>$mobile,
            'virtualMobile'=>$virtualMobile,//分配的商务号
            'bindTime'=>1,//当设置为X时（X大于0且小于1440），绑定时间X分钟，超过指定时间后将自动释放当设置为 （小于等于零） 时为长期绑定
           // 'isAllowAPP'=>1,
        ];
        $sign=$this->sign($params);
        $params['sign']=$sign;
        return   $this->postdata($uri,$params);
    }

    /**
     * @param string $mobile
     * @param string $virtualMobile
     * @return mixed|\Psr\Http\Message\StreamInterface|string
     * @throws ApiException
     */
    public function  unbindMobile(string $mobile,string $virtualMobile){//解除绑定手机
        $uri='unbindMobile.do';
        $params=[
            'id'=>$this->id,
            'timestamp'=>$this->createTimeStamp(),
            'virtualMobile'=>$virtualMobile,
        ];
        $sign=$this->sign($params);
        $params['bindMobile']= $mobile;
        $params['sign']=$sign;
        return   $this->postdata($uri,$params);
    }

    /**
     * @param string $virtualMobile
     * @param int $status
     * @return mixed|\Psr\Http\Message\StreamInterface|string
     * @throws ApiException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function onAndOffMobile(string  $virtualMobile,int $status){// 0：关机状态1：开机状态2：空号7：休假中(保密模式下有效)
        $uri='onAndOffMobile.do';
        $params=[
            'id'=>$this->id,
            'timestamp'=>$this->createTimeStamp(),
            'virtualMobile'=>$virtualMobile,
            'status'=>$status
        ];
        $sign=$this->sign($params);
        $params['sign']=$sign;
        return   $this->postdata($uri,$params);
    }
    public function notifyCallUrl($request){//通话推送
        $id=$request->id;
        $seqId=$request->seqId;
        $timestamp=$request->timestamp;
        $virtualMobile=$request->virtualMobile;
        $from=$request->from;
        $to=$request->to;
        $callStart=$request->callStart;//开始时间戳
        $callAnswer=$request->callAnswer;//接听时间
        $callEnd=$request->callEnd;//结束时间戳
        $mid=$request->mid;
        $call=$request->call;//0呼叫vm 1呼叫dm
        $status=$request->status;
        $noAnswerReason=$request->noAnswerReason;//未接听原因
        $sign=$request->sign;
        $params=compact('id','seqId','timestamp','virtualMobile','from','to','status');
       if($this->sign($params)!=$sign){
           throw  new TeleException('延签不通过');
       };
       $borkerCall= BrokerCall::where('mid',$mid)->first();
       if($borkerCall){
           return true;
       }
      $borkerCall= new BrokerCall();
      $borkerCall->virtualMobile=$virtualMobile;
      $borkerCall->from=$from;
      $borkerCall->seqId=$seqId;
      $borkerCall->callStart=$this->millisecondToDate($callStart);
      $borkerCall->callAnswer=$this->millisecondToDate($callAnswer);
      $borkerCall->callEnd=$this->millisecondToDate($callEnd);
      $borkerCall->mid=$mid;
      $borkerCall->status=$status;
      $borkerCall->to=$to;
      $borkerCall->call=$call;
      $borkerCall->noAnswerReason=$noAnswerReason;
      $borkerCall->save();

        //打完电话后解绑
        $this->unbindMobile($to,$virtualMobile);
        $brokerMobile = BrokerMobile::where("mobile",$virtualMobile)->first();
        $brokerMobile->is_bind = 0;
        $brokerMobile->save();

    }

    /**
     * @param $request
     * @return \Illuminate\Http\JsonResponse
     *
     */
    public function notifyMediaStream($request){//通话通知接口
        $id=$request->id;
        $timestamp=$request->timestamp;
        $readUrl=$request->readUrl;
        $mid=$request->mid;
        $tag=$request->tag;
        $getFileUrl=$request->getFileUrl;
        $sign=$request->sign;
        $params=compact('id','timestamp','readUrl','mid');

        if($this->sign($params)!=$sign){
          // throw  new TeleException('延签不通过');
        };

        $brokerMedia= BrokerMedia::where('mid',$mid)->first();
        if($brokerMedia){
           return true;
        }
        $brokerMedia=new BrokerMedia();
        $brokerMedia->readUrl=$readUrl;
        $brokerMedia->tag=$tag;
        $brokerMedia->mid=$mid;
        $brokerMedia->getFileUrl=$getFileUrl;
        $brokerMedia->save();
    }
    public function readFile($readUrl,$tag,$mid){
        $params=[
            'id'=>$this->id,
            'timestamp'=>$this->createTimeStamp(),
            'mid'=>$mid,
        ];
        $params['sign']=$this->sign($params);
        $params['tag']=$tag;
        $file=  $this->postFile($readUrl,$params);
        $file['data']=(new DesService())->decrypt($file['data']);
        return $file;

    }
    protected function millisecondToDate($millisecond){
        return date('Y-m-d H:i:s',(int)($millisecond/1000));
    }
    /**
     * @param string $virtualMobile
     * @param string $mobile
     * @param int $type
     * @return mixed|\Psr\Http\Message\StreamInterface|string
     * @throws ApiException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function setBlockMobile(string $virtualMobile,string $mobile,int $type=0,int $isDelete=0){//设置来电黑名单
        $uri='setBlockMobile.do';
        $params=[
            'id'=>$this->id,
            'timestamp'=>$this->createTimeStamp(),
            'virtualMobile'=>$virtualMobile,
            'blockMobile'=>$mobile,
            'type'=>$type,//0 关机 2 空号
            'isDelete'=>$isDelete,//0 增加黑名单 1 取消黑名单
        ];
        $sign=$this->sign($params);
        $params['sign']=$sign;
        return   $this->postdata($uri,$params);
    }
    /**
     * @param string $virtualMobile
     * @return mixed|\Psr\Http\Message\StreamInterface|string
     * @throws ApiException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function searchBindMobile(string $virtualMobile){//搜索绑定的真实手机
        $uri='searchBindMobile.do';
        $params=[
            'id'=>$this->id,
            'timestamp'=>$this->createTimeStamp(),
            'virtualMobile'=>$virtualMobile,
        ];
        $sign=$this->sign($params);
        $params['sign']=$sign;
        return   $this->postdata($uri,$params);
    }
    public function callTransfer(int  $seqId, string $fm,string $virtualMobile,string $tm){//6. 商务号外呼接口
        $uri='callTransfer.do';
        $params=[
            'id'=>$this->id,
            'seqId'=>$seqId,
            'fm'=>$fm,
            'vm'=>$virtualMobile,
            'tm'=>$tm,
            'bindTime'=>-1,
        ];
        $sign=$this->sign($params);
        $params['sign']=$sign;
        return   $this->postdata($uri,$params);
    }

    /**
     * @return int
     */
    protected  function createTimeStamp(){
       return  (int)(microtime(true)*1000);
    }
    /**
     * @param array $params
     * @return string
     */
    protected function sign(array  $params=['code'=>1]){
        $baseParams=['key'=>$this->key];
        $params=array_merge($baseParams,$params);
        return    md5(implode('',$params));
    }
    /**
     * @param $uri
     * @param $baseData
     * @return mixed|\Psr\Http\Message\StreamInterface|string
     * @throws ApiException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    protected function  postdata($uri,$baseData){
        //dd($this->url.$uri);

        $response = $this->client->request('post', $this->url . $uri, [
            'form_params' => $baseData
        ]);
        $body = $response->getBody();
        $body= $body->getContents();
        $body=  json_decode($body,true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new ApiException('Could not encrypt the data.');
        }
        if($body['result']!="0"){
            throw  new ApiException($body['error']);
        }
        return $body;
    }
    protected  function postFile($url,$baseData){
        $response = $this->client->request('post', $url, [
            'form_params' => $baseData
        ]);
        $body = $response->getBody();
        $body= $body->getContents();
        $body=  json_decode($body,true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new ApiException('Could not encrypt the data.');
        }
        if($body['result']!="0"){
            throw  new ApiException($body['error']);
        }
        return $body;
    }
}